A Netflix Analysis

Installing pacman

install.packages("pacman")
Error in install.packages : Updating loaded packages
library(pacman)

Loading the packages needed

pacman::p_load(dplyr,tidyverse,tidyr,  janitor, lubridate, ggplot2, leaflet, plotly, readxl)

Loading our dataset

netflix= read.csv("netflix_titles.csv")

Preview of our dataset

head(netflix, 5)

Lets check the column names

names(netflix)
 [1] "show_id"      "type"         "title"        "director"     "cast"         "country"      "date_added"  
 [8] "release_year" "rating"       "duration"     "listed_in"    "description"  "X"            "X.1"         
[15] "X.2"          "X.3"          "X.4"          "X.5"          "X.6"          "X.7"          "X.8"         
[22] "X.9"          "X.10"         "X.11"         "X.12"         "X.13"        

Lets look at each column and its datatype

str(netflix)
'data.frame':   8809 obs. of  26 variables:
 $ show_id     : chr  "s1" "s2" "s3" "s4" ...
 $ type        : chr  "Movie" "TV Show" "TV Show" "TV Show" ...
 $ title       : chr  "Dick Johnson Is Dead" "Blood & Water" "Ganglands" "Jailbirds New Orleans" ...
 $ director    : chr  "Kirsten Johnson" "" "Julien Leclercq" "" ...
 $ cast        : chr  "" "Ama Qamata, Khosi Ngema, Gail Mabalane, Thabang Molaba, Dillon Windvogel, Natasha Thahane, Arno Greeff, Xolile "| __truncated__ "Sami Bouajila, Tracy Gotoas, Samuel Jouy, Nabiha Akkari, Sofia Lesaffre, Salim Kechiouche, Noureddine Farihi, G"| __truncated__ "" ...
 $ country     : chr  "United States" "South Africa" "" "" ...
 $ date_added  : chr  "September 25, 2021" "September 24, 2021" "September 24, 2021" "September 24, 2021" ...
 $ release_year: int  2020 2021 2021 2021 2021 2021 2021 1993 2021 2021 ...
 $ rating      : chr  "PG-13" "TV-MA" "TV-MA" "TV-MA" ...
 $ duration    : chr  "90 min" "2 Seasons" "1 Season" "1 Season" ...
 $ listed_in   : chr  "Documentaries" "International TV Shows, TV Dramas, TV Mysteries" "Crime TV Shows, International TV Shows, TV Action & Adventure" "Docuseries, Reality TV" ...
 $ description : chr  "As her father nears the end of his life, filmmaker Kirsten Johnson stages his death in inventive and comical wa"| __truncated__ "After crossing paths at a party, a Cape Town teen sets out to prove whether a private-school swimming star is h"| __truncated__ "To protect his family from a powerful drug lord, skilled thief Mehdi and his expert team of robbers are pulled "| __truncated__ "Feuds, flirtations and toilet talk go down among the incarcerated women at the Orleans Justice Center in New Or"| __truncated__ ...
 $ X           : logi  NA NA NA NA NA NA ...
 $ X.1         : logi  NA NA NA NA NA NA ...
 $ X.2         : logi  NA NA NA NA NA NA ...
 $ X.3         : logi  NA NA NA NA NA NA ...
 $ X.4         : logi  NA NA NA NA NA NA ...
 $ X.5         : logi  NA NA NA NA NA NA ...
 $ X.6         : logi  NA NA NA NA NA NA ...
 $ X.7         : logi  NA NA NA NA NA NA ...
 $ X.8         : logi  NA NA NA NA NA NA ...
 $ X.9         : logi  NA NA NA NA NA NA ...
 $ X.10        : logi  NA NA NA NA NA NA ...
 $ X.11        : logi  NA NA NA NA NA NA ...
 $ X.12        : logi  NA NA NA NA NA NA ...
 $ X.13        : logi  NA NA NA NA NA NA ...

Lets convert the type to factor

netflix$type= as.factor(netflix$type)

Investigating Null values

NAs=colSums(is.na(netflix))
names(netflix)[NAs>0]
 [1] "X"    "X.1"  "X.2"  "X.3"  "X.4"  "X.5"  "X.6"  "X.7"  "X.8"  "X.9"  "X.10" "X.11" "X.12" "X.13"

Dim

dim(netflix)
[1] 8809   26

Total rows with NAs in each column

colSums(is.na(netflix))
     show_id         type        title     director         cast      country   date_added release_year 
           0            0            0            0            0            0            0            0 
      rating     duration    listed_in  description            X          X.1          X.2          X.3 
           0            0            0            0         8809         8809         8809         8809 
         X.4          X.5          X.6          X.7          X.8          X.9         X.10         X.11 
        8809         8809         8809         8809         8809         8809         8809         8809 
        X.12         X.13 
        8809         8809 

Since the columns with NAs dont have much meaning to the dataset we can remove them

netflix= netflix %>% 
  select(show_id,type,title,director,cast,country,date_added,release_year,rating,duration,listed_in,description)

Descriptive Statistics:

Summarize the distribution of the types of shows (Movies vs. TV Shows).

#Distribution of movie type
netflix_type= netflix %>% 
  select(type) %>% 
  group_by(type) %>% 
  summarise(totalcount= n())

# Calculate percentage labels
percentages <- round(netflix_type$totalcount / sum(netflix_type$totalcount) * 100, 1)
labels <- paste(netflix_type$type, percentages, "%", sep = " ")

# Create the pie chart using plotly
fig <- plot_ly(netflix_type, labels = ~type, values = ~totalcount, type = 'pie', 
               textinfo = 'label+percent',
               insidetextorientation = 'radial',
               marker = list(colors = c('red', 'green')))

# Customize the layout
fig <- fig %>% layout(title = 'Distribution of TV Shows and Movies')

# Display the plot
fig

Calculate the number of shows released per year.

netflix_releaseyear= netflix %>% 
  select(release_year, type) %>% 
  group_by(release_year, type) %>% 
  summarise(total_moveis_or_shows= n(), .groups = "drop")

netflix_release_year= netflix %>% 
  select(release_year, type) %>% 
  group_by(release_year) %>% 
  summarise(total_shows= n()) %>% 
  arrange(desc(total_shows)) %>% 
  head(10)

fig4=plot_ly(netflix_release_year, x= ~release_year, y= ~total_shows,type= 'bar',
             text= ~total_shows,
             textposition = "auto",
             marker=list(color="green")) %>% 
  layout(title= "Top 10 years with the highest number of shows produced",
         xaxis= list(title="Years"),
         yaxis= list(title="Total Shows"))
fig4

Analyze the distribution of ratings (e.g., TV-MA, PG-13, etc.).

netflix_ratings= netflix %>%
  select(rating) %>% 
  group_by(rating) %>% 
  summarize(total_rating=n())

#the plot
fig3 =plot_ly(netflix_ratings, x= ~rating, y= ~total_rating, type='bar', marker=list(color= "red"))%>% 
  layout(title="Distribution of the ratings",
         xaxis= list(title="Ratings"),
         yaxis= list(title="Total ratings"))

fig3

Trend Analysis:

Analyze the popularity of different genres over the years.

netflix_genre= netflix %>% 
  select(release_year, listed_in) %>% 
  group_by(release_year, listed_in) %>% 
  summarise(total_shows= n(), .groups = "drop")

Genre Analysis:

Determine the most common genres listed.

netflix_genre_common= netflix %>% 
  select(listed_in) %>% 
  group_by(listed_in) %>% 
  summarise(total_count= n()) %>% 
  arrange(desc(total_count)) %>% 
  head(10)

fig5 = plot_ly(netflix_genre_common, y= ~listed_in, x= ~total_count, type= 'bar',
               text= ~total_count,
               textposition= "auto",
               marker= list(color="orange")) %>% 
  layout(
    title= "Top 10 Most common genres Listed",
    yaxis = list(title="Genres"),
    xaxis = list(title="Total Count")
  )

fig5

Analyze the correlation between genres and ratings.

netflix_corr_genre= netflix %>% 
  select(listed_in, rating) %>% 
  group_by(listed_in, rating) %>% 
  summarise(total_count = n(), .groups = "drop")
 print(netflix_corr_genre)

Country Analysis:

Analyze the Countries With the most movies produced

netflix_country= netflix %>% 
  select(country) %>% 
  mutate(country= paste0(country, ","))

netflix_country = netflix_country %>% 
  separate(col= country, into= c("Country", "Rest"), sep=",")

netflix_country_grouped= netflix_country %>% 
  group_by(Country) %>% 
  summarise(Total_Movies= n()) %>% 
  arrange(desc(Total_Movies))
# Convert empty strings to NA in the 'Country' column
netflix_country_grouped_clean <- netflix_country_grouped %>%
  mutate(Country = na_if(Country, ""))

# Remove rows with NA values
netflix_country_grouped_clean <- na.omit(netflix_country_grouped_clean)
netflix_country_grouped_plot= head(netflix_country_grouped, 10)

fig8 = plot_ly(netflix_country_grouped_plot, x= ~ Country, y= ~Total_Movies, type= 'bar',
               text= ~Total_Movies,
               markers=list(color="yellow")) %>% 
  layout(
    title = "Top 10 Countries with the Highest No of movies Produced",
    xaxis = list(title= "Countries", tickangle= -45),
    yaxis = list(title= "Total Movies Produced"))
 fig8 
NA

Map

# # Get world map data for country coordinates
# world_map <- map_data("world")
# 
# # Prepare the data by merging with coordinates
# country_coords <- world_map %>%
#   group_by(region) %>%
#   summarize(
#     lat = mean(lat),
#     lng = mean(long)
#   ) %>%
#   rename(Country = region)
# 
# # Merge country data with coordinates
# map_data <- netflix_country_grouped_clean %>%
#   left_join(country_coords, by = "Country")
# 
# # Filter out rows with missing or invalid coordinates
# map_data_filtered <- map_data %>%
#   filter(!is.na(lat) & !is.na(lng))
# 
# # Create an interactive map with markers
# m <- leaflet(map_data_filtered) %>%
#   addTiles() %>%
#   addMarkers(
#     clusterOptions = markerClusterOptions(),
#     ~lng, ~lat,
#     popup = ~paste("<strong>Country:</strong>", Country, "<br>",
#                    "<strong>Value:</strong>", Total_Movies)
#   )
# 
# # Display the map
# m

Analyze the diversity of content by country.

United States

netflix_diversity= netflix %>% 
  select(country, listed_in) %>% 
  group_by(country, listed_in) %>% 
  summarise(total_count=n(), .groups = "drop") %>% 
  arrange(desc(total_count))
print(netflix_diversity)

Duration Analysis:

Compare the average duration of movies vs. TV shows.

netflix$duration= as.character(netflix$duration)

netflix_duration <- netflix %>%
  select(type, duration) %>%
  separate(col = duration, into = c("duration", "units"), sep = " ")

# Convert duration back to integer
netflix_duration$duration <- as.integer(netflix_duration$duration)

netflix_duration_compison_type= netflix_duration %>% 
  group_by(type) %>%
  summarise(Average_Duration= floor(mean(duration, na.rm = TRUE)))

print(netflix_duration_compison_type)

Analyze the distribution of the number of seasons for TV shows.

netflix_tvshows_distribution= netflix %>% 
  select(type, duration) %>% 
  filter(type == "TV Show") %>% 
  group_by(duration) %>% 
  summarise(Frequency_totals= n()) %>% 
  arrange(desc(Frequency_totals))

netflix_tvshows_distribution$duration= factor(netflix_tvshows_distribution$duration, levels= unique(netflix_tvshows_distribution$duration))
# Create a bar chart
fig6 = plot_ly(netflix_tvshows_distribution, x = ~duration, y= ~Frequency_totals, type = 'bar',
            marker=list(color="green")) %>%
  layout(
    title= "Distribution of Seasons in the TV Shows",
    xaxis= list(title ="Duration", tickangle=-45),
    yaxis= list(title= "Frequency")
  )

# Display the plot
fig6
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIEEgTmV0ZmxpeCBBbmFseXNpcw0KIyMjIyBJbnN0YWxsaW5nIHBhY21hbg0KYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0NCmluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQpsaWJyYXJ5KHBhY21hbikNCmBgYA0KIyMjIyBMb2FkaW5nIHRoZSBwYWNrYWdlcyBuZWVkZWQNCmBgYHtyfQ0KcGFjbWFuOjpwX2xvYWQoZHBseXIsdGlkeXZlcnNlLHRpZHlyLCAgamFuaXRvciwgbHVicmlkYXRlLCBnZ3Bsb3QyLCBsZWFmbGV0LCBwbG90bHksIHJlYWR4bCkNCmBgYA0KIyMjIyBMb2FkaW5nIG91ciBkYXRhc2V0DQpgYGB7cn0NCm5ldGZsaXg9IHJlYWQuY3N2KCJuZXRmbGl4X3RpdGxlcy5jc3YiKQ0KYGBgDQojIyMjIFByZXZpZXcgb2Ygb3VyIGRhdGFzZXQNCmBgYHtyfQ0KaGVhZChuZXRmbGl4LCA1KQ0KYGBgDQojIyMjIExldHMgY2hlY2sgdGhlIGNvbHVtbiBuYW1lcw0KYGBge3J9DQpuYW1lcyhuZXRmbGl4KQ0KYGBgDQojIyMjIExldHMgbG9vayBhdCBlYWNoIGNvbHVtbiBhbmQgaXRzIGRhdGF0eXBlDQpgYGB7cn0NCnN0cihuZXRmbGl4KQ0KYGBgDQojIyMjIExldHMgY29udmVydCB0aGUgdHlwZSB0byBmYWN0b3INCmBgYHtyfQ0KbmV0ZmxpeCR0eXBlPSBhcy5mYWN0b3IobmV0ZmxpeCR0eXBlKQ0KYGBgDQoNCiMjIyMgSW52ZXN0aWdhdGluZyBOdWxsIHZhbHVlcw0KYGBge3J9DQpOQXM9Y29sU3Vtcyhpcy5uYShuZXRmbGl4KSkNCm5hbWVzKG5ldGZsaXgpW05Bcz4wXQ0KYGBgDQojIyMjIERpbQ0KYGBge3J9DQpkaW0obmV0ZmxpeCkNCmBgYA0KIyMjIyBUb3RhbCByb3dzIHdpdGggTkFzIGluIGVhY2ggY29sdW1uDQpgYGB7cn0NCmNvbFN1bXMoaXMubmEobmV0ZmxpeCkpDQpgYGANCg0KIyMjIyBTaW5jZSB0aGUgY29sdW1ucyB3aXRoIE5BcyBkb250IGhhdmUgbXVjaCBtZWFuaW5nIHRvIHRoZSBkYXRhc2V0IHdlIGNhbiByZW1vdmUgdGhlbQ0KYGBge3J9DQpuZXRmbGl4PSBuZXRmbGl4ICU+JSANCiAgc2VsZWN0KHNob3dfaWQsdHlwZSx0aXRsZSxkaXJlY3RvcixjYXN0LGNvdW50cnksZGF0ZV9hZGRlZCxyZWxlYXNlX3llYXIscmF0aW5nLGR1cmF0aW9uLGxpc3RlZF9pbixkZXNjcmlwdGlvbikNCmBgYA0KDQojIyBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzOg0KIyMjIFN1bW1hcml6ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSB0eXBlcyBvZiBzaG93cyAoTW92aWVzIHZzLiBUViBTaG93cykuDQpgYGB7cn0NCiNEaXN0cmlidXRpb24gb2YgbW92aWUgdHlwZQ0KbmV0ZmxpeF90eXBlPSBuZXRmbGl4ICU+JSANCiAgc2VsZWN0KHR5cGUpICU+JSANCiAgZ3JvdXBfYnkodHlwZSkgJT4lIA0KICBzdW1tYXJpc2UodG90YWxjb3VudD0gbigpKQ0KDQojIENhbGN1bGF0ZSBwZXJjZW50YWdlIGxhYmVscw0KcGVyY2VudGFnZXMgPC0gcm91bmQobmV0ZmxpeF90eXBlJHRvdGFsY291bnQgLyBzdW0obmV0ZmxpeF90eXBlJHRvdGFsY291bnQpICogMTAwLCAxKQ0KbGFiZWxzIDwtIHBhc3RlKG5ldGZsaXhfdHlwZSR0eXBlLCBwZXJjZW50YWdlcywgIiUiLCBzZXAgPSAiICIpDQoNCiMgQ3JlYXRlIHRoZSBwaWUgY2hhcnQgdXNpbmcgcGxvdGx5DQpmaWcgPC0gcGxvdF9seShuZXRmbGl4X3R5cGUsIGxhYmVscyA9IH50eXBlLCB2YWx1ZXMgPSB+dG90YWxjb3VudCwgdHlwZSA9ICdwaWUnLCANCiAgICAgICAgICAgICAgIHRleHRpbmZvID0gJ2xhYmVsK3BlcmNlbnQnLA0KICAgICAgICAgICAgICAgaW5zaWRldGV4dG9yaWVudGF0aW9uID0gJ3JhZGlhbCcsDQogICAgICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9ycyA9IGMoJ3JlZCcsICdncmVlbicpKSkNCg0KIyBDdXN0b21pemUgdGhlIGxheW91dA0KZmlnIDwtIGZpZyAlPiUgbGF5b3V0KHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBUViBTaG93cyBhbmQgTW92aWVzJykNCg0KIyBEaXNwbGF5IHRoZSBwbG90DQpmaWcNCmBgYA0KIyMjIENhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIHNob3dzIHJlbGVhc2VkIHBlciB5ZWFyLg0KYGBge3J9DQpuZXRmbGl4X3JlbGVhc2V5ZWFyPSBuZXRmbGl4ICU+JSANCiAgc2VsZWN0KHJlbGVhc2VfeWVhciwgdHlwZSkgJT4lIA0KICBncm91cF9ieShyZWxlYXNlX3llYXIsIHR5cGUpICU+JSANCiAgc3VtbWFyaXNlKHRvdGFsX21vdmVpc19vcl9zaG93cz0gbigpLCAuZ3JvdXBzID0gImRyb3AiKQ0KDQpuZXRmbGl4X3JlbGVhc2VfeWVhcj0gbmV0ZmxpeCAlPiUgDQogIHNlbGVjdChyZWxlYXNlX3llYXIsIHR5cGUpICU+JSANCiAgZ3JvdXBfYnkocmVsZWFzZV95ZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0b3RhbF9zaG93cz0gbigpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyh0b3RhbF9zaG93cykpICU+JSANCiAgaGVhZCgxMCkNCg0KZmlnND1wbG90X2x5KG5ldGZsaXhfcmVsZWFzZV95ZWFyLCB4PSB+cmVsZWFzZV95ZWFyLCB5PSB+dG90YWxfc2hvd3MsdHlwZT0gJ2JhcicsDQogICAgICAgICAgICAgdGV4dD0gfnRvdGFsX3Nob3dzLA0KICAgICAgICAgICAgIHRleHRwb3NpdGlvbiA9ICJhdXRvIiwNCiAgICAgICAgICAgICBtYXJrZXI9bGlzdChjb2xvcj0iZ3JlZW4iKSkgJT4lIA0KICBsYXlvdXQodGl0bGU9ICJUb3AgMTAgeWVhcnMgd2l0aCB0aGUgaGlnaGVzdCBudW1iZXIgb2Ygc2hvd3MgcHJvZHVjZWQiLA0KICAgICAgICAgeGF4aXM9IGxpc3QodGl0bGU9IlllYXJzIiksDQogICAgICAgICB5YXhpcz0gbGlzdCh0aXRsZT0iVG90YWwgU2hvd3MiKSkNCmZpZzQNCmBgYA0KDQojIyMgQW5hbHl6ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHJhdGluZ3MgKGUuZy4sIFRWLU1BLCBQRy0xMywgZXRjLikuDQpgYGB7cn0NCm5ldGZsaXhfcmF0aW5ncz0gbmV0ZmxpeCAlPiUNCiAgc2VsZWN0KHJhdGluZykgJT4lIA0KICBncm91cF9ieShyYXRpbmcpICU+JSANCiAgc3VtbWFyaXplKHRvdGFsX3JhdGluZz1uKCkpDQoNCiN0aGUgcGxvdA0KZmlnMyA9cGxvdF9seShuZXRmbGl4X3JhdGluZ3MsIHg9IH5yYXRpbmcsIHk9IH50b3RhbF9yYXRpbmcsIHR5cGU9J2JhcicsIG1hcmtlcj1saXN0KGNvbG9yPSAicmVkIikpJT4lIA0KICBsYXlvdXQodGl0bGU9IkRpc3RyaWJ1dGlvbiBvZiB0aGUgcmF0aW5ncyIsDQogICAgICAgICB4YXhpcz0gbGlzdCh0aXRsZT0iUmF0aW5ncyIpLA0KICAgICAgICAgeWF4aXM9IGxpc3QodGl0bGU9IlRvdGFsIHJhdGluZ3MiKSkNCg0KZmlnMw0KYGBgDQojIyBUcmVuZCBBbmFseXNpczoNCiMjIyBFeHBsb3JlIHRoZSB0cmVuZHMgaW4gdGhlIG51bWJlciBvZiBzaG93cyBhZGRlZCB0byB0aGUgcGxhdGZvcm0gb3ZlciB0aW1lLg0KYGBge3J9DQpuZXRmbGl4X3JlbGVhc2VfeWVhcl9ncm91cD0gbmV0ZmxpeCAlPiUgDQogIHNlbGVjdChyZWxlYXNlX3llYXIsIHR5cGUpICU+JSANCiAgZ3JvdXBfYnkocmVsZWFzZV95ZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0b3RhbF9zaG93cz0gbigpKQ0KDQpuZXRmbGl4X3JlbGVhc2VfeWVhcl9ncm91cGVkPSBuZXRmbGl4X3JlbGVhc2VfeWVhcl9ncm91cCAlPiUgDQogIG11dGF0ZShyZWxlYXNlX3llYXJfZ3JvdXBlZD0gY2FzZV93aGVuKA0KICAgIHJlbGVhc2VfeWVhciA8IDE5MzAgfiAiMTkyMC0xOTMwIiwNCiAgICByZWxlYXNlX3llYXIgPCAxOTQwIH4gIjE5MzAtMTk0MCIsDQogICAgcmVsZWFzZV95ZWFyIDwgMTk1MCB+ICIxOTQwLTE5NTAiLA0KICAgIHJlbGVhc2VfeWVhciA8IDE5NjAgfiAiMTk1MC0xOTYwIiwNCiAgICByZWxlYXNlX3llYXIgPCAxOTcwIH4gIjE5NTAtMTk3MCIsDQogICAgcmVsZWFzZV95ZWFyIDwgMTk4MCB+ICIxOTcwLTE5ODAiLA0KICAgIHJlbGVhc2VfeWVhciA8IDE5OTAgfiAiMTk4MC0xOTkwIiwNCiAgICByZWxlYXNlX3llYXIgPCAyMDAwIH4gIjE5OTAtMjAwMCIsDQogICAgcmVsZWFzZV95ZWFyIDwgMjAxMCB+ICIyMDAwLTIwMTAiLA0KICAgIHJlbGVhc2VfeWVhciA8IDIwMjAgfiAiMjAxMC0yMDIwIiwNCiAgICByZWxlYXNlX3llYXIgPj0gMjAyMCB+ICIyMDIwIikpICU+JSANCiAgZ3JvdXBfYnkocmVsZWFzZV95ZWFyX2dyb3VwZWQpICU+JSANCiAgc3VtbWFyaXNlKHRvdGFsX3Nob3dzID0gc3VtKHRvdGFsX3Nob3dzKSkNCg0KI3VzaW5nIHBsb3RseSB0byBkcmF3IHRoZSBsaW5lIENoYXJ0DQpmaWcxIDwtIHBsb3RfbHkobmV0ZmxpeF9yZWxlYXNlX3llYXJfZ3JvdXBlZCwgeCA9IH5yZWxlYXNlX3llYXJfZ3JvdXBlZCwgeSA9IH50b3RhbF9zaG93cywgdHlwZSA9ICdzY2F0dGVyJywgbW9kZSA9ICdsaW5lcycpICU+JQ0KICBsYXlvdXQodGl0bGUgPSAnTmV0ZmxpeCBTaG93cyBieSBSZWxlYXNlIFllYXInLA0KICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gJ1JlbGVhc2UgWWVhcicsIHRpY2thbmdsZT0gLTQ1KSwNCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdUb3RhbCBTaG93cycpKQ0KDQojcHJpbnRpbmcgdGhlIHBsb3QNCmZpZzENCmBgYA0KDQojIyMgQW5hbHl6ZSB0aGUgcG9wdWxhcml0eSBvZiBkaWZmZXJlbnQgZ2VucmVzIG92ZXIgdGhlIHllYXJzLg0KYGBge3J9DQpuZXRmbGl4X2dlbnJlPSBuZXRmbGl4ICU+JSANCiAgc2VsZWN0KHJlbGVhc2VfeWVhciwgbGlzdGVkX2luKSAlPiUgDQogIGdyb3VwX2J5KHJlbGVhc2VfeWVhciwgbGlzdGVkX2luKSAlPiUgDQogIHN1bW1hcmlzZSh0b3RhbF9zaG93cz0gbigpLCAuZ3JvdXBzID0gImRyb3AiKQ0KYGBgDQojIyBHZW5yZSBBbmFseXNpczoNCiMjIyBEZXRlcm1pbmUgdGhlIG1vc3QgY29tbW9uIGdlbnJlcyBsaXN0ZWQuDQpgYGB7cn0NCm5ldGZsaXhfZ2VucmVfY29tbW9uPSBuZXRmbGl4ICU+JSANCiAgc2VsZWN0KGxpc3RlZF9pbikgJT4lIA0KICBncm91cF9ieShsaXN0ZWRfaW4pICU+JSANCiAgc3VtbWFyaXNlKHRvdGFsX2NvdW50PSBuKCkpICU+JSANCiAgYXJyYW5nZShkZXNjKHRvdGFsX2NvdW50KSkgJT4lIA0KICBoZWFkKDEwKQ0KDQpmaWc1ID0gcGxvdF9seShuZXRmbGl4X2dlbnJlX2NvbW1vbiwgeT0gfmxpc3RlZF9pbiwgeD0gfnRvdGFsX2NvdW50LCB0eXBlPSAnYmFyJywNCiAgICAgICAgICAgICAgIHRleHQ9IH50b3RhbF9jb3VudCwNCiAgICAgICAgICAgICAgIHRleHRwb3NpdGlvbj0gImF1dG8iLA0KICAgICAgICAgICAgICAgbWFya2VyPSBsaXN0KGNvbG9yPSJvcmFuZ2UiKSkgJT4lIA0KICBsYXlvdXQoDQogICAgdGl0bGU9ICJUb3AgMTAgTW9zdCBjb21tb24gZ2VucmVzIExpc3RlZCIsDQogICAgeWF4aXMgPSBsaXN0KHRpdGxlPSJHZW5yZXMiKSwNCiAgICB4YXhpcyA9IGxpc3QodGl0bGU9IlRvdGFsIENvdW50IikNCiAgKQ0KDQpmaWc1DQpgYGANCg0KIyMjIEFuYWx5emUgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gZ2VucmVzIGFuZCByYXRpbmdzLg0KYGBge3J9DQpuZXRmbGl4X2NvcnJfZ2VucmU9IG5ldGZsaXggJT4lIA0KICBzZWxlY3QobGlzdGVkX2luLCByYXRpbmcpICU+JSANCiAgZ3JvdXBfYnkobGlzdGVkX2luLCByYXRpbmcpICU+JSANCiAgc3VtbWFyaXNlKHRvdGFsX2NvdW50ID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKQ0KIHByaW50KG5ldGZsaXhfY29ycl9nZW5yZSkNCmBgYA0KDQojIyBDb3VudHJ5IEFuYWx5c2lzOg0KIyMjIEFuYWx5emUgdGhlIENvdW50cmllcyBXaXRoIHRoZSBtb3N0IG1vdmllcyBwcm9kdWNlZA0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpuZXRmbGl4X2NvdW50cnk9IG5ldGZsaXggJT4lIA0KICBzZWxlY3QoY291bnRyeSkgJT4lIA0KICBtdXRhdGUoY291bnRyeT0gcGFzdGUwKGNvdW50cnksICIsIikpDQoNCm5ldGZsaXhfY291bnRyeSA9IG5ldGZsaXhfY291bnRyeSAlPiUgDQogIHNlcGFyYXRlKGNvbD0gY291bnRyeSwgaW50bz0gYygiQ291bnRyeSIsICJSZXN0IiksIHNlcD0iLCIpDQoNCm5ldGZsaXhfY291bnRyeV9ncm91cGVkPSBuZXRmbGl4X2NvdW50cnkgJT4lIA0KICBncm91cF9ieShDb3VudHJ5KSAlPiUgDQogIHN1bW1hcmlzZShUb3RhbF9Nb3ZpZXM9IG4oKSkgJT4lIA0KICBhcnJhbmdlKGRlc2MoVG90YWxfTW92aWVzKSkNCiMgQ29udmVydCBlbXB0eSBzdHJpbmdzIHRvIE5BIGluIHRoZSAnQ291bnRyeScgY29sdW1uDQpuZXRmbGl4X2NvdW50cnlfZ3JvdXBlZF9jbGVhbiA8LSBuZXRmbGl4X2NvdW50cnlfZ3JvdXBlZCAlPiUNCiAgbXV0YXRlKENvdW50cnkgPSBuYV9pZihDb3VudHJ5LCAiIikpDQoNCiMgUmVtb3ZlIHJvd3Mgd2l0aCBOQSB2YWx1ZXMNCm5ldGZsaXhfY291bnRyeV9ncm91cGVkX2NsZWFuIDwtIG5hLm9taXQobmV0ZmxpeF9jb3VudHJ5X2dyb3VwZWRfY2xlYW4pDQpuZXRmbGl4X2NvdW50cnlfZ3JvdXBlZF9wbG90PSBoZWFkKG5ldGZsaXhfY291bnRyeV9ncm91cGVkLCAxMCkNCg0KZmlnOCA9IHBsb3RfbHkobmV0ZmxpeF9jb3VudHJ5X2dyb3VwZWRfcGxvdCwgeD0gfiBDb3VudHJ5LCB5PSB+VG90YWxfTW92aWVzLCB0eXBlPSAnYmFyJywNCiAgICAgICAgICAgICAgIHRleHQ9IH5Ub3RhbF9Nb3ZpZXMsDQogICAgICAgICAgICAgICBtYXJrZXJzPWxpc3QoY29sb3I9InllbGxvdyIpKSAlPiUgDQogIGxheW91dCgNCiAgICB0aXRsZSA9ICJUb3AgMTAgQ291bnRyaWVzIHdpdGggdGhlIEhpZ2hlc3QgTm8gb2YgbW92aWVzIFByb2R1Y2VkIiwNCiAgICB4YXhpcyA9IGxpc3QodGl0bGU9ICJDb3VudHJpZXMiLCB0aWNrYW5nbGU9IC00NSksDQogICAgeWF4aXMgPSBsaXN0KHRpdGxlPSAiVG90YWwgTW92aWVzIFByb2R1Y2VkIikpDQogZmlnOCANCg0KYGBgDQojIE1hcA0KYGBge3J9DQojICMgR2V0IHdvcmxkIG1hcCBkYXRhIGZvciBjb3VudHJ5IGNvb3JkaW5hdGVzDQojIHdvcmxkX21hcCA8LSBtYXBfZGF0YSgid29ybGQiKQ0KIyANCiMgIyBQcmVwYXJlIHRoZSBkYXRhIGJ5IG1lcmdpbmcgd2l0aCBjb29yZGluYXRlcw0KIyBjb3VudHJ5X2Nvb3JkcyA8LSB3b3JsZF9tYXAgJT4lDQojICAgZ3JvdXBfYnkocmVnaW9uKSAlPiUNCiMgICBzdW1tYXJpemUoDQojICAgICBsYXQgPSBtZWFuKGxhdCksDQojICAgICBsbmcgPSBtZWFuKGxvbmcpDQojICAgKSAlPiUNCiMgICByZW5hbWUoQ291bnRyeSA9IHJlZ2lvbikNCiMgDQojICMgTWVyZ2UgY291bnRyeSBkYXRhIHdpdGggY29vcmRpbmF0ZXMNCiMgbWFwX2RhdGEgPC0gbmV0ZmxpeF9jb3VudHJ5X2dyb3VwZWRfY2xlYW4gJT4lDQojICAgbGVmdF9qb2luKGNvdW50cnlfY29vcmRzLCBieSA9ICJDb3VudHJ5IikNCiMgDQojICMgRmlsdGVyIG91dCByb3dzIHdpdGggbWlzc2luZyBvciBpbnZhbGlkIGNvb3JkaW5hdGVzDQojIG1hcF9kYXRhX2ZpbHRlcmVkIDwtIG1hcF9kYXRhICU+JQ0KIyAgIGZpbHRlcighaXMubmEobGF0KSAmICFpcy5uYShsbmcpKQ0KIyANCiMgIyBDcmVhdGUgYW4gaW50ZXJhY3RpdmUgbWFwIHdpdGggbWFya2Vycw0KIyBtIDwtIGxlYWZsZXQobWFwX2RhdGFfZmlsdGVyZWQpICU+JQ0KIyAgIGFkZFRpbGVzKCkgJT4lDQojICAgYWRkTWFya2VycygNCiMgICAgIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMoKSwNCiMgICAgIH5sbmcsIH5sYXQsDQojICAgICBwb3B1cCA9IH5wYXN0ZSgiPHN0cm9uZz5Db3VudHJ5Ojwvc3Ryb25nPiIsIENvdW50cnksICI8YnI+IiwNCiMgICAgICAgICAgICAgICAgICAgICI8c3Ryb25nPlZhbHVlOjwvc3Ryb25nPiIsIFRvdGFsX01vdmllcykNCiMgICApDQojIA0KIyAjIERpc3BsYXkgdGhlIG1hcA0KIyBtDQoNCmBgYA0KIyMjIEFuYWx5emUgdGhlIGRpdmVyc2l0eSBvZiBjb250ZW50IGJ5IGNvdW50cnkuDQojIyMjIFVuaXRlZCBTdGF0ZXMNCmBgYHtyfQ0KbmV0ZmxpeF9kaXZlcnNpdHk9IG5ldGZsaXggJT4lIA0KICBzZWxlY3QoY291bnRyeSwgbGlzdGVkX2luKSAlPiUgDQogIGdyb3VwX2J5KGNvdW50cnksIGxpc3RlZF9pbikgJT4lIA0KICBzdW1tYXJpc2UodG90YWxfY291bnQ9bigpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgDQogIGFycmFuZ2UoZGVzYyh0b3RhbF9jb3VudCkpDQpwcmludChuZXRmbGl4X2RpdmVyc2l0eSkNCmBgYA0KIyMgRHVyYXRpb24gQW5hbHlzaXM6DQojIyMgQ29tcGFyZSB0aGUgYXZlcmFnZSBkdXJhdGlvbiBvZiBtb3ZpZXMgdnMuIFRWIHNob3dzLg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpuZXRmbGl4JGR1cmF0aW9uPSBhcy5jaGFyYWN0ZXIobmV0ZmxpeCRkdXJhdGlvbikNCg0KbmV0ZmxpeF9kdXJhdGlvbiA8LSBuZXRmbGl4ICU+JQ0KICBzZWxlY3QodHlwZSwgZHVyYXRpb24pICU+JQ0KICBzZXBhcmF0ZShjb2wgPSBkdXJhdGlvbiwgaW50byA9IGMoImR1cmF0aW9uIiwgInVuaXRzIiksIHNlcCA9ICIgIikNCg0KIyBDb252ZXJ0IGR1cmF0aW9uIGJhY2sgdG8gaW50ZWdlcg0KbmV0ZmxpeF9kdXJhdGlvbiRkdXJhdGlvbiA8LSBhcy5pbnRlZ2VyKG5ldGZsaXhfZHVyYXRpb24kZHVyYXRpb24pDQoNCm5ldGZsaXhfZHVyYXRpb25fY29tcGlzb25fdHlwZT0gbmV0ZmxpeF9kdXJhdGlvbiAlPiUgDQogIGdyb3VwX2J5KHR5cGUpICU+JQ0KICBzdW1tYXJpc2UoQXZlcmFnZV9EdXJhdGlvbj0gZmxvb3IobWVhbihkdXJhdGlvbiwgbmEucm0gPSBUUlVFKSkpDQoNCnByaW50KG5ldGZsaXhfZHVyYXRpb25fY29tcGlzb25fdHlwZSkNCmBgYA0KIyMjIEFuYWx5emUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgbnVtYmVyIG9mIHNlYXNvbnMgZm9yIFRWIHNob3dzLg0KYGBge3J9DQpuZXRmbGl4X3R2c2hvd3NfZGlzdHJpYnV0aW9uPSBuZXRmbGl4ICU+JSANCiAgc2VsZWN0KHR5cGUsIGR1cmF0aW9uKSAlPiUgDQogIGZpbHRlcih0eXBlID09ICJUViBTaG93IikgJT4lIA0KICBncm91cF9ieShkdXJhdGlvbikgJT4lIA0KICBzdW1tYXJpc2UoRnJlcXVlbmN5X3RvdGFscz0gbigpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhGcmVxdWVuY3lfdG90YWxzKSkNCg0KbmV0ZmxpeF90dnNob3dzX2Rpc3RyaWJ1dGlvbiRkdXJhdGlvbj0gZmFjdG9yKG5ldGZsaXhfdHZzaG93c19kaXN0cmlidXRpb24kZHVyYXRpb24sIGxldmVscz0gdW5pcXVlKG5ldGZsaXhfdHZzaG93c19kaXN0cmlidXRpb24kZHVyYXRpb24pKQ0KIyBDcmVhdGUgYSBiYXIgY2hhcnQNCmZpZzYgPSBwbG90X2x5KG5ldGZsaXhfdHZzaG93c19kaXN0cmlidXRpb24sIHggPSB+ZHVyYXRpb24sIHk9IH5GcmVxdWVuY3lfdG90YWxzLCB0eXBlID0gJ2JhcicsDQogICAgICAgICAgICBtYXJrZXI9bGlzdChjb2xvcj0iZ3JlZW4iKSkgJT4lDQogIGxheW91dCgNCiAgICB0aXRsZT0gIkRpc3RyaWJ1dGlvbiBvZiBTZWFzb25zIGluIHRoZSBUViBTaG93cyIsDQogICAgeGF4aXM9IGxpc3QodGl0bGUgPSJEdXJhdGlvbiIsIHRpY2thbmdsZT0tNDUpLA0KICAgIHlheGlzPSBsaXN0KHRpdGxlPSAiRnJlcXVlbmN5IikNCiAgKQ0KDQojIERpc3BsYXkgdGhlIHBsb3QNCmZpZzYNCmBgYA0K